package com.yuting.gateway.filter;

import com.yuting.gateway.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@RefreshScope
@Slf4j
public class LimitFilter implements GlobalFilter, Ordered {

    public Map<String, List<Long>> ipCache = new ConcurrentHashMap<>();

    @Value("${limit.maxLimitIpHit}")
    private Integer maxLimitIpHit = 1;

    @Value("${limit.checkLimitIpHitInterval}")
    private Integer checkLimitIpHitInterval = 2000;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String path = request.getURI().getPath();
        log.info("limitFilter ip-{}", request.getRemoteAddress().getHostString());
        boolean register = CommonUtil.isRegister(path);
        log.info("limitFilter register-{}", register);
        if(register){

            String ip = request.getRemoteAddress().getHostString();

            boolean ipLimited = isIpLimited(ip);
            if(ipLimited){
                response.setStatusCode(HttpStatus.valueOf(303));
                String data = "您频繁进⾏注册，请求已被拒绝";
                DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                return response.writeWith(Mono.just(wrap));
            }
        }


        return chain.filter(exchange);
    }



    // 是否超过最大限制
    private boolean isOverMaxLimit(Integer nowCount) {
        return nowCount > maxLimitIpHit;
    }
    private boolean isIpLimited(String reqIp) {
        //先清除无效访问记录
        List<Long> longs = ipCache.get(reqIp);
        log.info("record-{}", longs);
        long now = System.currentTimeMillis();
        if(longs != null){
            log.info("ip-{}  count-{}", reqIp, longs.size());
            longs.add(now);
            Collections.sort(longs);
            long lastStartCheckTime = now - checkLimitIpHitInterval;
            int index = 0;
            for(int i = 0; i <= longs.size() - 1; i++){
                if(longs.get(i) >= lastStartCheckTime){
                    index = i;
                    break;
                }
            }
            longs = longs.subList(index, longs.size());

            // 将有效计数更新回计数器,删除无效计数后，在限制范围内，则不限制操作
            if(!isOverMaxLimit(longs.size())) {
                return false;
            }
        }else{
            List<Long> record = new ArrayList<>();
            record.add(now);
            ipCache.put(reqIp, record);
            return false;
        }

        return true;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
